package xcore

import (
	"context"
	"fmt"
	"gitee.com/go-mid/infra/xlog"
	"sort"
	"strconv"
	"strings"
	"time"
)

//计算t1到t2相隔的天数,不足一天为0天
func DaysInterval(start, end time.Time) int {
	var neg int = 1
	if start.After(end) {
		neg = -1
		start, end = end, start
	}
	start = time.Date(start.Year(), start.Month(), start.Day(), 0, 0, 0, 0, time.Local)
	end = time.Date(end.Year(), end.Month(), end.Day(), 0, 0, 0, 0, time.Local)
	subhour := end.Sub(start).Hours()
	return int(subhour/24) * neg
}

//取指定时间当天开始的时间
func BeginOfSameDayAsTime(currentTime time.Time) time.Time {
	return time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), 0, 0, 0, 0, currentTime.Location())
}

//指定时间当天的最后一秒
func LastSecondOfSameDayAsTime(currentTime time.Time) time.Time {
	return time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), 23, 59, 59, 0, currentTime.Location())

}

//-1 标识无效的年龄
func Age(ctx context.Context, second int64) int {
	birth := time.Unix(second, 0).Local()
	now := time.Now().Local()
	birthYear := birth.Year()
	birthMonth := birth.Month()
	birthDay := birth.Day()

	nowYear := now.Year()
	nowMonth := now.Month()
	nowDay := now.Day()

	age := nowYear - birthYear
	if age < 0 || age > 200 {
		return -1
	}
	if nowMonth < birthMonth {
		age--
		return validAge(age)
	}
	if nowMonth > birthMonth {
		return age
	}
	if nowDay < birthDay {
		age--
		return validAge(age)
	}
	if nowDay >= birthDay {
		return age
	}
	return validAge(age)
}
func validAge(age int) int {
	if age < 0 || age > 200 {
		return -1
	}
	return age
}

//获取时间返回
type TimeRange struct {
	From HhMmSs
	To   HhMmSs
}

func (m TimeRange) Contain(other HhMmSs) bool {
	isCross := m.isCrossDay()
	otherSec := other.ToSecond()
	if isCross {
		return m.From.ToSecond() <= otherSec || m.To.ToSecond() >= otherSec
	}
	return m.From.ToSecond() <= otherSec && m.To.ToSecond() >= otherSec
}

func (m TimeRange) isCrossDay() bool {
	return m.From.ToSecond() > m.To.ToSecond()
}

type HhMmSs struct {
	Hour   uint64
	Minute uint64
	Second uint64
}

func (m HhMmSs) ToSecond() uint64 {
	return m.Hour*3600 + m.Minute*60 + m.Second
}

//解析时间范围，格式为 HH:mm:ss~HH:mm:ss;HH:mm:ss~HH:mm:ss 如，03:10:00~10:20:00;20:30:00~01:20:00,
//其中to如果比from小，则认为跨天了
func InTimeRange(ctx context.Context, timeRangeConf string, current HhMmSs) (bool, error) {
	timeRanges := ParseTimeRange(ctx, timeRangeConf)
	if len(timeRanges) == 0 {
		return false, fmt.Errorf("no timerange")
	}
	sort.Slice(timeRanges, func(i, j int) bool {
		return timeRanges[i].From.ToSecond() < timeRanges[j].From.ToSecond()
	})
	for _, timeRange := range timeRanges {
		if timeRange == nil {
			continue
		}
		if timeRange.Contain(current) {
			return true, nil
		}
	}
	return false, nil
}
func ParseTimeRange(ctx context.Context, timeRangeConf string) []*TimeRange {
	hmConfs := strings.Split(timeRangeConf, ";")
	if len(hmConfs) == 0 {
		return nil
	}
	var ranges []*TimeRange
	for _, hmConf := range hmConfs {
		timeRange := parseOneTimerange(ctx, hmConf)
		if timeRange != nil {
			ranges = append(ranges, timeRange)
		}
	}
	return ranges
}
func parseOneTimerange(ctx context.Context, timeRangeConf string) *TimeRange {
	hmConfs := strings.Split(timeRangeConf, "~")
	if len(hmConfs) != 2 {
		return nil
	}
	fromConf := strings.TrimSpace(hmConfs[0])
	toConf := strings.TrimSpace(hmConfs[1])
	from, err := parseHourMinute(ctx, fromConf)
	if err != nil {
		xlog.Warnf(ctx, "parseHourMinute error: fromconf: %s, err: %v", fromConf, err)
		return nil
	}
	to, err := parseHourMinute(ctx, toConf)
	if err != nil {
		xlog.Warnf(ctx, "parseHourMinute error: toconf: %s, err: %v", toConf, err)
		return nil
	}
	return &TimeRange{
		From: from,
		To:   to,
	}
}

//HH:mm:ss
func parseHourMinute(ctx context.Context, hourMinute string) (HhMmSs, error) {
	conf := strings.TrimSpace(hourMinute)
	hm := strings.Split(conf, ":")
	if len(hm) != 3 {
		return HhMmSs{}, fmt.Errorf("invalid hour minute second: %s", conf)
	}
	hourStr := hm[0]
	minuStr := hm[1]
	secStr := hm[2]
	hour, err := strconv.ParseInt(hourStr, 10, 64)
	if err != nil {
		return HhMmSs{}, err
	}
	minu, err := strconv.ParseInt(minuStr, 10, 64)
	if err != nil {
		return HhMmSs{}, err
	}
	sec, err := strconv.ParseInt(secStr, 10, 64)
	if err != nil {
		return HhMmSs{}, err
	}
	return HhMmSs{
		Hour:   uint64(hour),
		Minute: uint64(minu),
		Second: uint64(sec),
	}, nil
}
